#include "ASTBuilder.h"
#include "ScriptCompiler/ASTBuilder/GlobalNamespaceBuilder.h"

#include "ScriptCompiler/ScriptFileContext.h"
#include "ScriptCompiler/CompilerContext.h"

void BuildAST(std::shared_ptr<CScriptFileContext> InContext)
{
    auto RootBuilder=std::make_shared<CGlobalNamespaceBuilder>(InContext);

    RootBuilder->ReadCurentToken();
    
    if(InContext->Compiler.lock()-> ErrorInfo.IsErrorOccured())
    {
        InContext->Compiler.lock()-> ErrorInfo.Print();
        return;
    }


    InContext->ASTRoot = RootBuilder->Result;

    InContext->ASTRoot->DebugPrint(-1);
}

TOptional<uint64_t> IASTBuilder::FindPairedBrace(std::shared_ptr<CScriptFileContext> InContext)
{
    return FindPairedToken(EScriptTokenType::LeftBrace, EScriptTokenType::RightBrace, InContext);
}

TOptional<uint64_t> IASTBuilder::FindPairedBrace(int32_t InStartIndex, std::shared_ptr<CScriptFileContext> InContext)
{
    return FindPairedToken(EScriptTokenType::LeftBrace, EScriptTokenType::RightBrace, InStartIndex, InContext);
}

TOptional<uint64_t> IASTBuilder::FindPairedParentheses(std::shared_ptr<CScriptFileContext> InContext)
{
    return FindPairedToken(EScriptTokenType::LeftParentheses, EScriptTokenType::RightParentheses, InContext);
}

TOptional<uint64_t> IASTBuilder::FindPairedParentheses(int32_t InStartIndex, std::shared_ptr<CScriptFileContext> InContext)
{
    return FindPairedToken(EScriptTokenType::LeftParentheses, EScriptTokenType::RightParentheses, InStartIndex ,InContext);
}

TOptional<uint64_t> IASTBuilder::FindPairedBracket(std::shared_ptr<CScriptFileContext> InContext)
{
    return FindPairedToken(EScriptTokenType::LeftBracket, EScriptTokenType::RightBracket, InContext);
}

TOptional<uint64_t> IASTBuilder::FindPairedBracket(int32_t InStartIndex, std::shared_ptr<CScriptFileContext> InContext)
{
return FindPairedToken(EScriptTokenType::LeftBracket, EScriptTokenType::RightBracket,InStartIndex, InContext);
}

TOptional<uint64_t> IASTBuilder::FindPairedAngleBracket(std::shared_ptr<CScriptFileContext> InContext)
{
    return FindPairedToken(EScriptTokenType::Less, EScriptTokenType::Greater, InContext);
}

TOptional<uint64_t> IASTBuilder::FindPairedAngleBracket(int32_t InStartIndex, std::shared_ptr<CScriptFileContext> InContext)
{
    return FindPairedToken(EScriptTokenType::Less, EScriptTokenType::Greater,InStartIndex, InContext);
}

TOptional<uint64_t> IASTBuilder::FindNextToken(EScriptTokenType TokenType, std::shared_ptr<CScriptFileContext> InContext)
{
    uint64_t TokenIndex = InContext->CurrentTokenIndex;

    while (TokenIndex< InContext->TokenList.Num() )
    {
        auto Token = InContext->GetToken(TokenIndex);

        if (Token->Type == TokenType)
        {
            return TokenIndex;
        }

        TokenIndex++;
    }

    return TOptional<uint64_t>();

}

TOptional<uint64_t> IASTBuilder::FindNextToken(EScriptTokenType TokenType, std::shared_ptr<CScriptFileContext> InContext, uint64_t InEndIndex)
{
    uint64_t TokenIndex = InContext->CurrentTokenIndex;

    while (TokenIndex < InEndIndex)
    {
        auto Token = InContext->GetToken(TokenIndex);

        if (Token->Type == TokenType)
        {
            return TokenIndex;
        }

        TokenIndex++;
    }

    return TOptional<uint64_t>();
}

TOptional<uint64_t> IASTBuilder::FindNextToken(TVector<EScriptTokenType> TokenTypes, std::shared_ptr<CScriptFileContext> InContext, uint64_t InStartIndex, uint64_t InEndIndex)
{
    uint64_t TokenIndex = InStartIndex;

    while (TokenIndex < InEndIndex)
    {
        auto Token = InContext->GetToken(TokenIndex);

        if(TokenTypes.Contains(Token->Type))
        {
            return TokenIndex;
        }
       
        TokenIndex++;
    }

    return TOptional<uint64_t>();
}

TOptional<uint64_t> IASTBuilder::FindNextAssigmentOperator(std::shared_ptr<CScriptFileContext> InContext, uint64_t InEndIndex)
{
    uint64_t TokenIndex = InContext->CurrentTokenIndex;

    while (TokenIndex < InEndIndex)
    {
        auto Token = InContext->GetToken(TokenIndex);

        if (Token->Type == EScriptTokenType::Assign
            || Token->Type == EScriptTokenType::PlusAssign
            || Token->Type == EScriptTokenType::MinusAssign
            || Token->Type == EScriptTokenType::MultiplyAssign
            || Token->Type == EScriptTokenType::DivideAssign
        )
        {
            return TokenIndex;
        }

        TokenIndex++;
    }

    return TOptional<uint64_t>();

}

TOptional<uint64_t> IASTBuilder::FindPairedToken(EScriptTokenType LeftTokenType, EScriptTokenType RightTokenType, std::shared_ptr<CScriptFileContext> InContext)
{
    return FindPairedToken(LeftTokenType, RightTokenType, InContext->CurrentTokenIndex, InContext);
    // uint64_t InLeftNums=1;

    // uint64_t TokenIndex = InContext->CurrentTokenIndex;

    // while (TokenIndex< InContext->TokenList.Num())
    // {
    //     auto Token = InContext->GetToken(TokenIndex);

    //     if (Token->Type == LeftTokenType)
    //     {
    //         InLeftNums++;
    //     }
    //     else if (Token->Type == RightTokenType)
    //     {
    //         InLeftNums--;
    //     }

    //     if (InLeftNums == 0)
    //     {
    //         return TokenIndex;
    //     }

    //     TokenIndex++;
    // }

    // return TOptional<uint64_t>();
}

TOptional<uint64_t> IASTBuilder::FindPairedToken(EScriptTokenType LeftTokenType, EScriptTokenType RightTokenType, int32_t InStartIndex, std::shared_ptr<CScriptFileContext> InContext)
{
    uint64_t InLeftNums = 1;

    uint64_t TokenIndex = InStartIndex;

    while (TokenIndex < InContext->TokenList.Num())
    {
        auto Token = InContext->GetToken(TokenIndex);

        if (Token->Type == LeftTokenType)
        {
            InLeftNums++;
        }
        else if (Token->Type == RightTokenType)
        {
            InLeftNums--;
        }

        if (InLeftNums == 0)
        {
            return TokenIndex;
        }

        TokenIndex++;
    }

    return TOptional<uint64_t>();
}
